#include "tftp_server.h"
#include "error.h"
#include "stm32l052_lp_mode.h"
/*private variable*************************************************************************************/
extern uint8_t bleDataBufRx[600];
extern uint8_t bleDataBufTx[600];
extern volatile uint32_t ble_last_connect_time;
//tftp_server_plugin_t* plugin = NULL;
volatile int plugin_i = 0;
tftp_server_plugin_t tftp_plugins;
/*private function*************************************************************************************/
static void tftp_end(void);
static void send_ack(uint16_t blk);
static void send_data(uint16_t blk);
static void send_error(uint16_t error, char* msg);

extern bool _erase_cmd_open(char* name, uint8_t mode);

extern tftp_server_plugin_t tftp_server_plugin_erase_cmd;
extern tftp_server_plugin_t tftp_server_plugin_ota_image;
extern tftp_server_plugin_t tftp_server_plugin_parameter_cmd;
extern tftp_server_plugin_t tftp_server_plugin_sensor_read_cmd;
extern tftp_server_plugin_t tftp_server_plugin_voltage_read_cmd;
extern tftp_server_plugin_t tftp_server_plugin_time_cmd;
extern tftp_server_plugin_t tftp_server_plugin_systerm_reset_cmd;
extern tftp_server_plugin_t tftp_server_plugin_ble_address_cmd;
extern tftp_server_plugin_t tftp_server_plugin_sysinfo;
extern tftp_server_plugin_t tftp_server_plugin_raw_data_read_cmd;

uint8_t test_buf;


bool _test_open(char* name, uint8_t mode)
{
    if (0 == strcmp(name, "test")) {
        return true;
    } else {
        return false;
    }
}

uint16_t (_test_read)(uint8_t blk, uint8_t* buffer)
{
//    static uint8_t flag = 0;
// 
    if (blk == 0x01) {
//        memcpy(buffer, test_buf, 512);
//        if(flag == 20){
//           return 10;
//        }
//        else if(flag < 20){
//           flag++;
           return 512;
//        }else{
//           return 0;
//        }
//        return sprintf((char*)buffer, "tftp is working!");
    } else {
        return 0;
    }
}

void (_test_write)(uint8_t blk, uint8_t* buffer, uint16_t len)
{
#if PRINTF_DEBUG
    int i;
    for (i=0; i<len; i++) {
        printf("%c", buffer[i]);
    }
    printf("\n");
#endif
    BSP_LED_Toggle(LED5);
}

void (_test_close)(void)
{
}

tftp_server_plugin_t tftp_server_plugin_test = {
    _test_open,
    _test_read,
    _test_write,
    _test_close,
};

static tftp_server_plugin_t* plugins[] = {
    &tftp_server_plugin_erase_cmd,
    &tftp_server_plugin_ota_image,
    &tftp_server_plugin_parameter_cmd,
    &tftp_server_plugin_sensor_read_cmd,
    &tftp_server_plugin_voltage_read_cmd,
    &tftp_server_plugin_time_cmd,
    &tftp_server_plugin_sysinfo,
    &tftp_server_plugin_raw_data_read_cmd,
    &tftp_server_plugin_ble_address_cmd,
    &tftp_server_plugin_systerm_reset_cmd,
    &tftp_server_plugin_test,
   
};

const uint8_t tftp_server_plugins_count =
    sizeof(plugins) / sizeof(plugins[0]);

void tftp_server_input(void)
{
    
    uint16_t opcode;
    uint16_t blk;
    uint8_t* data;
    uint16_t datalen;
    char* filename;
    uint8_t *m = udp_hdr_rx->payload;

    opcode = ((uint16_t)m[0] << 8) | m[1];
    blk = ((uint16_t)m[2] << 8) | m[3];
    data = &m[4];
    datalen = udp_payload_len_rx - 4;
    
    if (opcode == TFTP_RRQ || opcode == TFTP_WRQ) {
               
        filename = (char*) &m[2];
        
#if TFTP_DEBUG
        printf("tftp filename = %s\n", filename);
#endif
        // find plugin to handle the request
        for (plugin_i=0; plugin_i<tftp_server_plugins_count; plugin_i++) {
            if (plugins[plugin_i]->open(filename, opcode)) break;
        }

        if (plugin_i == tftp_server_plugins_count) {
            char msg[80];
            sprintf(msg, "no plugin to handle file [%s]", filename);
            send_error(TFTP_ERR_FILE_NOT_FOUND, msg);
            return;
        }
       
    }
    
 switch (opcode) {
		case TFTP_RRQ:
			send_data(1);
			break;
		case TFTP_WRQ:
			send_ack(0);
			break;
		case TFTP_DATA:
#if TFTP_DEBUG
			printf("tftp_server recv blk=%d, len=%d\n", blk, datalen);
#endif			
			plugins[plugin_i]->write(blk, data, datalen);

			send_ack(blk);
			
			if (datalen < 512) {
				tftp_end();
			}
			
			break;
		case TFTP_ACK:
			send_data(blk + 1);
			break;
		default:
			app_fault_handle(APP_TFTP_OPCODE_ERROR);
			break;
    }
}

static void tftp_end(void)
{
 extern volatile uint32_t schedule_time;
#if TFTP_DEBUG
    printf("tftp_end\n");
#endif
 
 ble_last_connect_time = schedule_time;
 plugins[plugin_i]->close();
 
}

static void send_ack(uint16_t blk)
{
    uint8_t *m = udp_hdr_tx->payload;

    m[0] = 0;
    m[1] = TFTP_ACK;
    m[2] = (blk >> 8) & 0xff;
    m[3] = blk & 0xff;
    
    app_tftp_to_ip(4);
#ifdef TFTP_DEBUG
    printf("TFTP ack \n");
#endif
}

static void send_error(uint16_t error, char* msg)
{
    uint8_t *m = udp_hdr_tx->payload;
    uint16_t msglen;

    msglen = strlen(msg);

    m[0] = 0;
    m[1] = TFTP_ERROR;
    m[2] = (error >> 8) & 0xff;
    m[3] = error & 0xff;
    memcpy(m + 4, msg, msglen + 1);

    app_tftp_to_ip( msglen + 5);
}

static void send_data(uint16_t blk)
{
    uint8_t *m = &bleDataBufTx[8];
    uint16_t len;

    m[0] = 0;
    m[1] = TFTP_DATA;
    m[2] = (blk >> 8) & 0xff;
    m[3] = blk & 0xff;

    len = plugins[plugin_i]->read(blk, m + 4);
    
    if(len == 0x00){

    }
     
    app_tftp_to_ip(len + 4);
    if(len < 512)
        tftp_end();
 
}



